package com.kehutong.auth.service;

import com.kehutong.auth.entity.Account;
import com.kehutong.auth.enums.AccountStatus;
import com.kehutong.auth.enums.RegChannel;
import com.kehutong.common.DoveClient;
import com.kehutong.common.entity.Root;
import com.kehutong.common.enums.Gender;
import com.kehutong.common.util.Token;
import org.coraframework.authz.Subject;
import org.coraframework.authz.SubjectUtil;
import org.coraframework.bean.Beans;
import org.coraframework.inject.Inject;
import org.coraframework.json.JSONArray;
import org.coraframework.json.JSONObject;
import org.coraframework.logger.Logger;
import org.coraframework.logger.LoggerFactory;
import org.coraframework.mvc.http.Bean;
import org.coraframework.mvc.http.ReqMapping;
import org.coraframework.mvc.http.result.JSONResult;
import org.coraframework.mvc.http.result.Result;
import org.coraframework.mvc.webservice.WebService;
import org.coraframework.orm.Pool;
import org.coraframework.orm.jdbc.JdbcSession;
import org.coraframework.orm.jdbc.Page;
import org.coraframework.orm.jdbc.execute.entity.FindPage;
import org.coraframework.util.EnumUtil;
import org.coraframework.util.IDGenerate;
import org.coraframework.util.Objects;

import java.util.*;

/**
 * 账户服务
 *
 * @author: liukunlong
 * @date: 2021-04-09 17:24
 */
@WebService("/auth/account/service")
public class AccountService {
    static final Logger logger = LoggerFactory.getLogger(AccountService.class);
    @Inject
    private DoveClient doveClient;

    @Inject
    private JdbcSession jdbcSession;

    @Inject
    private SmsCodeService smsCodeService;

    /**
     * 绑定账号对应的物业公司编号
     *
     * @param id        账号编号
     * @param companyNo 公司编号
     */
    @ReqMapping("/bindAccountCompanyNo")
    public Object bindAccountCompanyNo(String id, String companyNo) throws Exception {
        Account account = jdbcSession.findById(Account.class, id);
        if (Objects.isNull(account)) {
            return Result.error(1, "账号信息不存在");
        }
        Set<String> khtIds = new HashSet<>();
        //获取账户已经绑定的公司编号集合
        if (Objects.nonEmpty(account.getKhtIds())) {
            khtIds = new HashSet<>(account.getKhtIds());
        }
        khtIds.add(companyNo);
        account.setKhtIds(new ArrayList<>(khtIds));
        jdbcSession.updateById(account);
        return Result.success(account);
    }

    /**
     * 新增或更新账户
     *
     * @param jsonObject 信息对象
     * @return 数据结果
     */
    @ReqMapping("/saveOrUpdateAccount")
    public Object saveOrUpdateAccount(JSONObject jsonObject) throws Exception{
        logger.info("saveOrUpdateAccount:################################################Begin=" + jsonObject);
        jsonObject.remove("token");
        String genderId=jsonObject.getString("gender");
        String regChannelVal=jsonObject.getString("regChannel");

        String accountName = jsonObject.getString("account");
        //String idCard = jsonObject.getString("idCard");
        String mobile = jsonObject.getString("mobile");
        String id = jsonObject.getString("id");
        String unionid=jsonObject.getString("unionid");
        String externalUserId=jsonObject.getString("externalUserId");

        //根据unionId来匹配账户是否存(同步企微住户数据有用到)
        if(Objects.nonEmpty(unionid)){
            logger.info("触发企业微信外部联系人数据同步,Current unionid is: {} and name is: {}",unionid);
            //获取小程序相关接口
            JSONObject rs = doveClient.post("/kht-bin/wechat/getMemberMap", http -> {
                http.addParam("unionid",unionid);
            });
            logger.info("根据unionid获取账号绑定,结果是:{}",rs);
            if(Objects.nonNull(rs)){
                int code = rs.getIntValue("code");
                if (code != 200) {
                    logger.error("根据unionid获取账号绑定结果错误:{}",rs.getString("message"));
                    return Result.error(code, rs.getString("message"));
                }
                JSONObject memberMap = rs.getJSONObject("data");
                if(Objects.nonEmpty(memberMap)){
                    String khtId=memberMap.getString("khtId");
                    id=khtId;
                    jsonObject.put("id",khtId);
                    logger.info("根据unionid匹配到账号数据,id is:{}",id);
                }

            }else{
                regChannelVal=RegChannel.WORK_WEIXIN_PROGRAM.getId();
                logger.info("企业微信同步客户联系人注册的账号,注册来源:企业微信.");
            }
        }

        Account account = jdbcSession.findOne(Account.class)
                .markBegin()
                .eq("id", id).or()
                .eq("account", accountName).or()
                //.eq("idCard", idCard).or()
                .eq("mobile", mobile).or()
                .markEnd().exe();

        if (Objects.isNull(account)) {
            account = Pool.newInstance(Account.class, id);
            Beans.from(jsonObject).to(account).exclude("id").igornNull().copy();
            //如果不存在账号则系统生成账号
            if (Objects.isEmpty(account.getAccount())) {
                account.setAccount(IDGenerate.nextId());
            }

            if(Objects.nonEmpty(genderId)){
                Gender gender= EnumUtil.getEnum(Gender.class,genderId);
                account.setGender(gender);
            }else{
                account.setGender(Gender.NOMORE);
            }

            if(Objects.nonEmpty(regChannelVal)){
                RegChannel regChannel= EnumUtil.getEnum(RegChannel.class,regChannelVal);
                account.setRegChannel(regChannel);
            }else{
                account.setRegChannel(RegChannel.MINI_PROGRAM);
            }

            account.setStatus(AccountStatus.ACTIVE);
            account.setMobileValid(true);
            jdbcSession.insert(account);
            //增加企微外部联系人绑定关系
            if(Objects.nonEmpty(unionid) && Objects.nonEmpty(externalUserId)){
                saveWxMember(unionid,id,account.getKhtIds().get(0),"",externalUserId);
            }
        } else {
            Set<String> khtIds = new HashSet<>();
            //获取账户已经绑定的公司编号集合
            if (Objects.nonEmpty(account.getKhtIds())) {
                khtIds = new HashSet<>(account.getKhtIds());
            }
            //更新物业住户信息的手机号,不级联更新账号的手机号,更新账号手机号需要走认证流程
            jsonObject.remove("mobile");
            Beans.from(jsonObject).to(account).exclude("id").igornNull().copy();
            //如果有传递过来公司编号则合并公司编号集合然后进行更新
            if (Objects.nonEmpty(account.getKhtIds())) {
                khtIds.addAll(new HashSet<>(account.getKhtIds()));
                account.setKhtIds(new ArrayList<>(khtIds));
            }

            if(Objects.nonEmpty(genderId)){
                Gender gender= EnumUtil.getEnum(Gender.class,genderId);
                account.setGender(gender);
            }
            logger.info("update account=" + account);
            jdbcSession.updateById(account);

            //增加企微外部联系人绑定关系
            if(Objects.nonEmpty(unionid) && Objects.nonEmpty(externalUserId)){
                saveWxMember(unionid,account.getId(),account.getKhtIds().get(0),"",externalUserId);
            }
        }
        logger.info("saveOrUpdateAccount######################################################################end");
        return Result.success(account);
    }


    /**
     * 企业微信同步外部联系人增加或更新账号绑定微信数据
     * @param unionid 关联
     * @param khtId 账号标志
     * @param companyNo 公司编号
     * @param companyName 公司名称
     * @param externalUserId 外部联系人ID
     * @throws Exception
     */
    private void saveWxMember(String unionid,String khtId,String companyNo,String companyName,String externalUserId) throws Exception {
        String accountNo = "";
        JSONObject saveOrUpdateAccountResult = doveClient.post("/kht-bin/wechat/saveWxMember", (http) -> {
            JSONObject body = new JSONObject();
            body.put("unionid", unionid);
            body.put("khtId", khtId);
            body.put("companyNo", companyNo);
            body.put("companyName", companyName);
            body.put("externalUserId", externalUserId);
            http.setBody(body.toJSONString());
        });
        if (saveOrUpdateAccountResult.getIntValue("code") != 200) {
            logger.error("WeChatService.saveWxMember 企业微信同步外部联系人增加账号绑定数据.");
        }
    }

    @ReqMapping("/list")
    public Object list(JSONObject jsonObject) {
        return jdbcSession.findArray(Account.class)
                .eq(jsonObject, "account", "realname", "email", "idCard", "mobile")
                .in(jsonObject, "id")
                .order("createTime", "desc")
                .exe();
    }

    @ReqMapping("/get")
    public Object get(Account account) {
        return account;
    }

    @ReqMapping("/getByIdList")
    public Object getByIdList(String idList) {
        String[] idArray = idList.split(",");
        return jdbcSession.findArray(Account.class).in("id", Arrays.asList(idArray)).exe();
    }

    @ReqMapping("/page")
    public Page<Account> page(JSONObject jsonObject) throws Exception{

        FindPage<Account> findPage=jdbcSession.findPage(Account.class)
                .like(jsonObject,"khtIds","realname","mobile")
                .eq(jsonObject,"idCard","regChannel");
        String search = jsonObject.getString("search");
        if(Objects.nonEmpty(search)){
            findPage.markBegin();
            findPage.like("id", search).or();
            findPage.like("realname", search).or();
            findPage.like("mobile", search).or();
            findPage.markEnd();
        }
        //传入的标签名称如果没有匹配到人则传入默认值，做权限限制
        String tagName=jsonObject.getString("tagName");
        if(Objects.nonEmpty(tagName)){
            List<String> ids=getTagUser(tagName);
            if(Objects.nonEmpty(ids)){
                findPage.in("id",ids);
            }else{
                findPage.eq("id",Root.ROOT_ID);
            }
        }
        findPage.between("createTime", jsonObject, "createTime", "createTime");
        findPage.page(jsonObject);
        findPage.order("createTime");
        Page<Account> page=findPage.exe();
        List<Account> accountList=page.getList();
        //构建每个用户的关联项目的数量,占不支持管理员查看关联小区数量
        if(Objects.nonEmpty(accountList)){
            JSONObject condition = new JSONObject();
            Subject subject = SubjectUtil.getSubject();
            for(Account account:accountList){
                account.setLastLoginTime(account.getUpdateTime());
                condition.put("residentNo",account.getId());
                //当前登录人不是超级管理员
                if (!Root.isRoot(subject.getUserId())) {
                    JSONObject countMap=getUserCommunityCount(condition);
                    account.setCommunityCount(countMap.getLongValue("count"));
                    account.setCommunityName(countMap.getString("name"));
                    account.setEnable(countMap.getBooleanValue("enable"));
                }
            }
        }

        return page;
    }


    /**
     * 获取包含当前标签的用户
     * @param tagName
     * @return
     * @throws Exception
     */
    private List<String> getTagUser(String tagName) throws Exception {
        List<String> result=new ArrayList<>();
        Map<String, String> mapping = new HashMap<>();
        JSONObject tagResult = doveClient.post("/crm/user/tag/service/list", (http) -> {
            JSONObject body = new JSONObject();
            body.put("tagName", tagName);
            http.setBody(body.toJSONString());
        });
        JSONArray userTagList=tagResult.getJSONArray("data");
        if(Objects.nonEmpty(userTagList)){
            for (Object userTagObj : userTagList) {
                JSONObject userTag = (JSONObject) userTagObj;
                result.add(userTag.getString("userNo"));
            }
        }
        return result;
    }

    /**
     * 获取用户关联小区数量
     * @param jsonObject
     * @return
     * @throws Exception
     */
    private JSONObject getUserCommunityCount(JSONObject jsonObject) throws Exception {
        JSONObject systemTagResult = doveClient.post("/crm/assets/user/service/count", http -> {
            http.setBody(jsonObject.toJSONString());
        });
        return systemTagResult.getJSONObject("data");
    }

    @ReqMapping("/getByCorpId")
    public Page<Account> getByCorpId(JSONObject jsonObject) {
        FindPage<Account> findPage=jdbcSession.findPage(Account.class).findInSet("khtIds", jsonObject.getString("khtId"));
        findPage.page(jsonObject);
        findPage.order("createTime");
        return findPage.exe();
    }

    @ReqMapping("/getAccount")
    public Object getAccount(JSONObject jsonObject)  throws Exception{
        String unionId=jsonObject.getString("unionId");
        if(Objects.nonEmpty(unionId)){
            //获取小程序相关接口
            JSONObject rs = doveClient.post("/kht-bin/wechat/getMemberMap", http -> {
                http.addParam("unionid",unionId);
            });
            int code = rs.getIntValue("code");
            if (code != 200) {
                return Result.error(code, rs.getString("message"));
            }
            JSONObject memberMap = rs.getJSONObject("data");
            if(Objects.isEmpty(memberMap)){
                return Result.error(1,"unionId:"+unionId+"没有绑定账号数据");
            }
            String khtId=memberMap.getString("khtId");
            jsonObject.put("id",khtId);
        }

        return jdbcSession.findOne(Account.class)
                .eq(jsonObject, "id","account", "email", "idCard", "mobile")
                .order("createTime", "desc")
                .exe();
    }


    @Bean(newInstance = true, copy = true)
    @ReqMapping("/save")
    public Object save(Account account) {
        jdbcSession.insert(account);
        return account;
    }

    @Bean(copy = true)
    @ReqMapping("/update")
    public Object update(Account account) {
        jdbcSession.updateById(account);

        return Result.success();
    }

    @ReqMapping("/delete")
    public Object delete(Account account) throws Exception {
        account.setStatus(AccountStatus.CANCEL);
        jdbcSession.updateById(account);
        return Result.success();
    }


    /**
     * 修改账号手机号
     *
     * @param account 账号对象
     * @return 结果
     * @throws Exception 异常
     */
    @Bean(copy = true)
    @ReqMapping("/updateAccountMobile")
    public Object updateAccountMobile(Account account, Token token) throws Exception {
        if (Objects.isNull(token)) {
            return Result.unlogin();
        }
        String code = account.getCode();
        if (Objects.isEmpty(code)) {
            return Result.error(1, "短信验证码不能为空.");
        }
        //短信发送校验
        JSONResult checkSmsCodeResult = (JSONResult) smsCodeService.checkSmsCode(token.getSessionId(), code);
        if (checkSmsCodeResult.getCode() != 200) {
            return Result.error(0, checkSmsCodeResult.getMessage());
        }
        //新输入手机号唯一校验
        List<Account> dbAccountList = jdbcSession.findArray(Account.class)
                .eq("mobile", account.getMobile())
                .eq("mobileValid", true)
                .noEq("id", account.getId())
                .eq("deleted", false).exe();
        //如果发现当前手机号被其他账户账号则将占用账号的手机更新成已失效
        if (Objects.nonEmpty(dbAccountList)) {
            for (Account dbAccount : dbAccountList) {
                dbAccount.setMobileValid(false);
                jdbcSession.updateById(dbAccount);
                //TODO 是否级联更新账号绑定过物业住户手机号数据为已失效？
            }
        }
        account.setMobileValid(true);
        jdbcSession.updateById(account);
        return Result.success();
    }
}
